<?php

declare(strict_types=1);

namespace App\Services;

use App\Helpers\File;
use App\Repositories\ContactRepository;
use App\Validations\ContactValidation;
use InvalidArgumentException;

class ContactService extends BaseService
{
    private const PHOTO_PATH = __DIR__.'/../../writable/contact';

    /**
     * Obtiene una instancia de las reglas de validación de los contactos.
     */
    private function contactValidation(): ContactValidation
    {
        return new ContactValidation;
    }

    /**
     * Obtiene una instancia del repositorio de contactos.
     */
    private function contactRepository(): ContactRepository
    {
        return new ContactRepository;
    }

    /**
     * Obtiene la información de todos los contactos del usuario con paginación.
     */
    public function getAllUserContactsWithPagination(string $userId): array
    {
        return $this->contactRepository()->getAllByUserIdWithPagination($userId);
    }

    /**
     * Registra la información del contacto de un usuario.
     */
    public function registerUserContact(string $userId, array $data): string
    {
        $fields = array_keys($data);
        $contactValidation = $this->contactValidation();

        // Obtiene las reglas de validación obligatorias.
        $rules = $contactValidation->getRules(['fullname', 'phone', 'user_id'], true);

        // Valida la información del contacto.
        $this->gump()->validation_rules(array_merge($contactValidation->getRules($fields), $rules));
        $this->gump()->filter_rules($contactValidation->getFilters($fields));

        $data = $this->gump()->run(array_merge($data, ['user_id' => $userId]));

        // Comprueba si existen errores de validación.
        if ($this->gump()->errors()) {
            throw new InvalidArgumentException('La información de registro del contacto es incorrecto');
        }

        // Elimina campos con strings vacíos.
        foreach ($fields as $field) {
            if (empty($data[$field]) && is_string($data[$field])) {
                unset($data[$field]);
            }
        }

        // Elimina campos innecesarios para insertar.
        unset($data['user_id']);

        $photo = $data['photo'] ?? null;

        // Genera un nombre único para la foto.
        $data['photo'] = isset($photo) && $photo['error'] === UPLOAD_ERR_OK
            ? File::generateRandomName($photo['name']) : null;

        // Registra la información del contacto.
        $id = $this->contactRepository()->insertByUserId($userId, $data);

        // Almacena la foto del contacto.
        if (isset($data['photo'])) {
        }

        return $id;
    }

    /**
     * Obtiene la información detallada del contacto de un usuario.
     */
    public function getUserContactDetails(string $contactId, string $userId): array
    {
        // Valida la información del contacto.
        $this->gump()->validation_rules($this->contactValidation()->getRules(['id', 'user_id']));
        $this->gump()->run(['id' => $contactId, 'user_id' => $userId]);

        // Comprueba si existen errores de validación.
        if ($this->gump()->errors()) {
            throw new InvalidArgumentException('El identificador del contacto o del usuario es incorrecto');
        }

        $contact = $this->contactRepository()->findDetailsByIdAndUserId($contactId, $userId);

        if (empty($contact)) {
            throw new InvalidArgumentException('No se encontró la información del contacto');
        }

        return $contact;
    }

    /**
     * Modifica la información del contacto de un usuario.
     */
    public function updateUserContact(string $contactId, string $userId, array $data): void
    {
        $fields = array_keys($data);
        $contactValidation = $this->contactValidation();

        // Obtiene las reglas de validación obligatorias.
        $rules = $contactValidation->getRules(['id', 'fullname', 'phone', 'user_id'], true);

        // Valida la información del contacto.
        $this->gump()->validation_rules(array_merge($contactValidation->getRules($fields), $rules));
        $this->gump()->filter_rules($contactValidation->getFilters($fields));

        $data = $this->gump()->run(array_merge($data, ['id' => $contactId, 'user_id' => $userId]));

        // Comprueba si existen errores de validación.
        if ($this->gump()->errors()) {
            throw new InvalidArgumentException('La información de modificación del contacto es incorrecto');
        }

        // Establece los campos con strings vacíos a null.
        foreach ($fields as $field) {
            if (empty($data[$field]) && is_string($data[$field])) {
                $data[$field] = null;
            }
        }

        // Elimina campos innecesarios para modificar.
        foreach (['id', 'user_id'] as $field) {
            unset($data[$field]);
        }

        $photo = $data['photo'] ?? null;

        // Genera un nombre único para la foto.
        $data['photo'] = isset($photo) && $photo['error'] === UPLOAD_ERR_OK
            ? File::generateRandomName($photo['name']) : null;

        if (empty($data['photo'])) {
            unset($data['photo']);
        }

        // Almacena la nueva foto del contacto.
        if (isset($data['photo'])) {
        }

        $this->contactRepository()->updateByUserId($contactId, $userId, $data);
    }

    /**
     * Elimina la información del contacto de un usuario.
     */
    public function deleteUserContact(string $contactId, string $userId): void
    {
        // Valida la información del contacto.
        $this->gump()->validation_rules($this->contactValidation()->getRules(['id', 'user_id']));
        $this->gump()->run(['id' => $contactId, 'user_id' => $userId]);

        // Comprueba si existen errores de validación.
        if ($this->gump()->errors()) {
            throw new InvalidArgumentException('El identificador del contacto o del usuario es incorrecto');
        }

        // Elimina la foto del contacto.
        if (isset($photo)) {
        }

        $this->contactRepository()->deleteByIdAndUserId($contactId, $userId);
    }
}
